package biz

import (
	"context"
	"fmt"
	"math"

	"github.com/go-kratos/kratos/v2/log"
)

// PointsUsecase 积分业务逻辑
type PointsUsecase struct {
	userRepo   UserRepo
	pointsRepo PointsRepo
	log        *log.Helper
}

// NewPointsUsecase 创建积分业务逻辑实例
func NewPointsUsecase(userRepo UserRepo, pointsRepo PointsRepo, logger log.Logger) *PointsUsecase {
	return &PointsUsecase{
		userRepo:   userRepo,
		pointsRepo: pointsRepo,
		log:        log.NewHelper(logger),
	}
}

// AddPointsForConsumption 消费成功后赠送积分
func (uc *PointsUsecase) AddPointsForConsumption(ctx context.Context, userID int64, orderID int64, amount float64, orderType string) (int64, int64, error) {
	// 参数验证
	if userID <= 0 {
		return 0, 0, ErrInvalidUserID
	}
	if amount <= 0 {
		return 0, 0, ErrInvalidAmount
	}

	// 检查用户是否存在
	user, err := uc.userRepo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return 0, 0, err
	}
	if user == nil {
		return 0, 0, ErrUserNotExists
	}

	// 检查用户状态
	if user.Status != 1 {
		return 0, 0, ErrUserDisabled
	}

	// 获取积分规则
	rule, err := uc.pointsRepo.GetPointsRule(ctx, "consumption")
	if err != nil {
		uc.log.Errorf("获取积分规则失败: %v", err)
		return 0, 0, err
	}

	if !rule.Enabled {
		return 0, 0, ErrPointsRuleDisabled
	}

	// 检查最小消费金额
	if amount < float64(rule.MinAmount) {
		uc.log.Infof("消费金额%.2f元不足最小消费金额%d元", amount, rule.MinAmount)
		return 0, 0, ErrAmountTooSmall
	}

	// 计算积分
	pointsToAdd := int64(math.Floor(amount * rule.Rate))

	// 检查最大积分限制
	if rule.MaxPoints > 0 && pointsToAdd > rule.MaxPoints {
		pointsToAdd = rule.MaxPoints
	}

	if pointsToAdd <= 0 {
		return 0, 0, ErrNoPointsToAdd
	}

	// 添加积分记录
	description := fmt.Sprintf("消费%.2f元获得积分", amount)
	err = uc.pointsRepo.AddPoints(ctx, userID, pointsToAdd, "consumption", description, orderID)
	if err != nil {
		uc.log.Errorf("添加积分记录失败: %v", err)
		return 0, 0, err
	}

	// 更新用户积分
	err = uc.userRepo.UpdatePoints(ctx, userID, pointsToAdd)
	if err != nil {
		uc.log.Errorf("更新用户积分失败: %v", err)
		return 0, 0, err
	}

	// 获取用户当前总积分
	totalPoints, err := uc.pointsRepo.GetUserPoints(ctx, userID)
	if err != nil {
		uc.log.Errorf("获取用户积分失败: %v", err)
		return pointsToAdd, 0, err
	}

	uc.log.Infof("用户%d消费%.2f元，获得%d积分，当前总积分%d", userID, amount, pointsToAdd, totalPoints)

	return pointsToAdd, totalPoints, nil
}

// AddPointsForCheckin 签到获取积分
func (uc *PointsUsecase) AddPointsForCheckin(ctx context.Context, userID int64) (int64, int64, int32, error) {
	// 参数验证
	if userID <= 0 {
		return 0, 0, 0, ErrInvalidUserID
	}

	// 检查用户是否存在
	user, err := uc.userRepo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return 0, 0, 0, err
	}
	if user == nil {
		return 0, 0, 0, ErrUserNotExists
	}

	// 检查用户状态
	if user.Status != 1 {
		return 0, 0, 0, ErrUserDisabled
	}

	// 获取签到积分规则
	rule, err := uc.pointsRepo.GetPointsRule(ctx, "checkin")
	if err != nil {
		uc.log.Errorf("获取签到积分规则失败: %v", err)
		return 0, 0, 0, err
	}

	if !rule.Enabled {
		return 0, 0, 0, ErrPointsRuleDisabled
	}

	// 签到获得积分
	pointsToAdd := int64(rule.Rate)

	// 添加积分记录
	description := "每日签到获得积分"
	err = uc.pointsRepo.AddPoints(ctx, userID, pointsToAdd, "checkin", description, 0)
	if err != nil {
		uc.log.Errorf("添加签到积分记录失败: %v", err)
		return 0, 0, 0, err
	}

	// 更新用户积分
	err = uc.userRepo.UpdatePoints(ctx, userID, pointsToAdd)
	if err != nil {
		uc.log.Errorf("更新用户积分失败: %v", err)
		return 0, 0, 0, err
	}

	// 获取用户当前总积分
	totalPoints, err := uc.pointsRepo.GetUserPoints(ctx, userID)
	if err != nil {
		uc.log.Errorf("获取用户积分失败: %v", err)
		return pointsToAdd, 0, 1, err
	}

	// 简化处理：连续签到天数默认为1
	checkinDays := 1

	uc.log.Infof("用户%d签到成功，获得%d积分，当前总积分%d", userID, pointsToAdd, totalPoints)

	return pointsToAdd, totalPoints, int32(checkinDays), nil
}

// UsePoints 使用积分
func (uc *PointsUsecase) UsePoints(ctx context.Context, userID int64, points int64, purpose string) (bool, int64, error) {
	// 参数验证
	if userID <= 0 {
		return false, 0, ErrInvalidUserID
	}
	if points <= 0 {
		return false, 0, ErrInvalidAmount
	}
	if purpose == "" {
		purpose = "积分使用"
	}

	// 检查用户是否存在
	user, err := uc.userRepo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return false, 0, err
	}
	if user == nil {
		return false, 0, ErrUserNotExists
	}

	// 检查用户状态
	if user.Status != 1 {
		return false, 0, ErrUserDisabled
	}

	// 获取用户当前积分
	currentPoints, err := uc.pointsRepo.GetUserPoints(ctx, userID)
	if err != nil {
		uc.log.Errorf("获取用户积分失败: %v", err)
		return false, 0, err
	}

	// 检查积分是否足够
	if currentPoints < points {
		uc.log.Warnf("用户%d积分不足，当前积分%d，需要积分%d", userID, currentPoints, points)
		return false, currentPoints, ErrInsufficientPoints
	}

	// 添加积分使用记录（负数表示使用）
	err = uc.pointsRepo.AddPoints(ctx, userID, -points, "use", purpose, 0)
	if err != nil {
		uc.log.Errorf("添加积分使用记录失败: %v", err)
		return false, currentPoints, err
	}

	// 更新用户积分
	err = uc.userRepo.UpdatePoints(ctx, userID, -points)
	if err != nil {
		uc.log.Errorf("更新用户积分失败: %v", err)
		return false, currentPoints, err
	}

	remainingPoints := currentPoints - points

	uc.log.Infof("用户%d使用%d积分，用途：%s，剩余积分%d", userID, points, purpose, remainingPoints)

	return true, remainingPoints, nil
}

// GetPointsHistory 获取积分历史记录
func (uc *PointsUsecase) GetPointsHistory(ctx context.Context, userID int64, page, pageSize int) ([]*PointsRecord, int, error) {
	return uc.pointsRepo.GetPointsHistory(ctx, userID, page, pageSize)
}

// GetPointsRules 获取积分规则
func (uc *PointsUsecase) GetPointsRules(ctx context.Context) ([]*PointsRule, error) {
	// 从数据层获取所有规则
	return uc.pointsRepo.GetPointsRules(ctx)
}

// GetUserPointsSummary 获取用户积分汇总信息
func (uc *PointsUsecase) GetUserPointsSummary(ctx context.Context, userID int64) (*PointsSummary, error) {
	// 参数验证
	if userID <= 0 {
		return nil, ErrInvalidUserID
	}

	// 检查用户是否存在
	user, err := uc.userRepo.GetByID(ctx, userID)
	if err != nil {
		uc.log.Errorf("查询用户失败: %v", err)
		return nil, err
	}
	if user == nil {
		return nil, ErrUserNotExists
	}

	// 获取用户当前积分
	currentPoints, err := uc.pointsRepo.GetUserPoints(ctx, userID)
	if err != nil {
		uc.log.Errorf("获取用户积分失败: %v", err)
		return nil, err
	}

	// 简化处理：暂时不统计月度数据
	summary := &PointsSummary{
		UserID:        userID,
		CurrentPoints: currentPoints,
		MonthlyEarned: 0,
		MonthlyUsed:   0,
		TotalEarned:   currentPoints,
	}

	return summary, nil
}

// PointsSummary 积分汇总信息
type PointsSummary struct {
	UserID        int64 `json:"user_id"`
	CurrentPoints int64 `json:"current_points"`
	MonthlyEarned int64 `json:"monthly_earned"`
	MonthlyUsed   int64 `json:"monthly_used"`
	TotalEarned   int64 `json:"total_earned"`
}

// 错误定义
var (
	ErrPointsRuleDisabled    = &BusinessError{Code: 5001, Message: "积分规则已禁用"}
	ErrAmountTooSmall        = &BusinessError{Code: 5002, Message: "消费金额不足"}
	ErrNoPointsToAdd         = &BusinessError{Code: 5003, Message: "无积分可添加"}
	ErrInsufficientPoints    = &BusinessError{Code: 5004, Message: "积分不足"}
	ErrInvalidUserID         = &BusinessError{Code: 5005, Message: "无效的用户ID"}
	ErrInvalidAmount         = &BusinessError{Code: 5006, Message: "无效的金额"}
	ErrOrderAlreadyProcessed = &BusinessError{Code: 5007, Message: "订单已处理过积分"}
	ErrAlreadyCheckedIn      = &BusinessError{Code: 5008, Message: "今日已签到"}
)
